# -*-coding: Utf-8 -*-
# @File : py_sdk_minio .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time：2023/8/13
import os
import pytz
from datetime import timedelta
from minio import Minio
from minio.commonconfig import CopySource
from minio.deleteobjects import DeleteObject
from minio.error import MinioException
from PIL import Image


# 桶相关操作
class BucketOperation(object):

    def __init__(self, endpoint, access_key, secret_key, bucket_name, secure=False):
        '''

        :param endpoint: IP:PORT(必传)
        :param access_key: 访问key,类似于用户名(必传)
        :param secret_key: 访问密钥,类似于密码(必传)
        :param bucket_name: 初识桶名(必传)
        :param secure: 以安全模式创建Minio连接,建议默认为 False (可选)
        :param back_dict: 反馈信息字典
                result : 执行成功/失败
                tag_bucket_name ：当前桶名
                msg ： 返回的单条消息
        '''
        self.endpoint = endpoint
        self.access_key = access_key
        self.secret_key = secret_key
        self.secure = secure
        self.bucket_name = bucket_name
        self.back_dict = {"result": True, "tag_bucket_name": "", "msg": "", "msg_list": []}
        self.minioClient = Minio(
            endpoint=endpoint,
            access_key=access_key,
            secret_key=secret_key,
            secure=secure
        )

    # 校验目标桶名
    def get_tag_bucket_name(self, tag_bucket_name=None):
        '''
        :param tag_bucket_name: 校验桶名
        :return: 返回桶名
        '''
        self.back_dict['tag_bucket_name'] = tag_bucket_name
        if tag_bucket_name:
            return tag_bucket_name
        else:
            return self.bucket_name

    # 创建桶 / 校验桶
    def create_bucket(self, tag_bucket_name=None):
        '''
        :param tag_bucket_name: 目标桶名,默认是初始化的桶名,可以自创建桶
        :return:
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            if self.minioClient.bucket_exists(bucket_name=tag_bucket_name):  # bucket_exists：检查桶是否存在
                self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 已经存在"
                return self.back_dict
            else:
                self.minioClient.make_bucket(tag_bucket_name)
                self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 创建成功"
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"初始化存储桶失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 列出所有的存储桶 list_buckets函数
    def get_bucket_list(self, tag_bucket_name=None):

        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            buckets = self.minioClient.list_buckets()
            for bucket in buckets:
                bucket_dict = {}
                bucket_dict['bucket_name'] = bucket.name
                bucket_create_time_utc = bucket.creation_date
                bucket_create_time_sh = bucket_create_time_utc.astimezone(pytz.timezone('Asia/Shanghai'))  # 获取中国北京时区的信息
                bucket_dict['bucket_create_time_utc'] = bucket_create_time_utc.strftime("%Y-%m-%d %H:%M:%S")
                bucket_dict['bucket_create_time_sh'] = bucket_create_time_sh.strftime("%Y-%m-%d %H:%M:%S")
                self.back_dict['msg_list'].append(bucket_dict)
            self.back_dict['msg'] = '存储桶列表获取成功'
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"获取桶列表失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 删除存储桶（单个存储桶）
    def get_remove_bucket(self, tag_bucket_name):
        '''

        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        try:
            self.minioClient.remove_bucket(tag_bucket_name)
            self.back_dict['tag_bucket_name'] = self.bucket_name
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 删除成功"
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 删除失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 列出目标存储桶中所有对象  或者使用 list_objects_v2也可
    def get_bucket_files(self, tag_bucket_name=None):
        '''

        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            self.back_dict['msg_list'] = []
            object_dict = {}
            # prefix用于过滤的对象名称前缀
            # objects = self.minioClient.list_objects('my_bucket', prefix='photos/') #  列出指定前缀开头的对象
            # objects = self.minioClient.list_objects('my_bucket', prefix='photos/', recursive=False) # 仅列举指定前缀下的直接对象，不递归子目录
            objects = self.minioClient.list_objects(tag_bucket_name, prefix=None, recursive=True)
            for obj in objects:
                object_dict['obj_bucket_name'] = obj.bucket_name
                object_dict['obj_name'] = obj.object_name
                bucket_create_time_utc = obj.last_modified
                bucket_create_time_sh = bucket_create_time_utc.astimezone(pytz.timezone('Asia/Shanghai'))  # 获取中国北京时区的信息
                object_dict['last_modified_utc'] = bucket_create_time_utc.strftime("%Y-%m-%d %H:%M:%S")
                object_dict['last_modified_sh'] = bucket_create_time_sh.strftime("%Y-%m-%d %H:%M:%S")
                # etag : 对象的唯一标识符
                object_dict['etag'] = obj.etag
                object_dict['size'] = obj.size
                object_dict['content_type'] = obj.content_type
                self.back_dict['msg_list'].append(object_dict)
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 获取所有对象成功"
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 获取所有对象失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 列出存储桶中未完整上传的对象(废弃)
    def get_list_incomplete_uploads(self, tag_bucket_name=None):
        '''

        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            uploads = self.minioClient.list_incomplete_uploads(tag_bucket_name, prefix=None, recursive=True)
            for obj in uploads:
                res = f'当前存储桶:>> {obj.bucket_name} 文件名:>> {obj.object_name} 上传id:>> {obj.upload_id} 文件大小:>> {obj.size}'
                print(res)
        except MinioException as err:
            res = f"温馨提示 : 出错啦!错误是 :>>{err}"
            print(res)

    # 获取存储桶的当前策略
    def bucket_policy(self, tag_bucket_name=None):
        '''

        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            policy = self.minioClient.get_bucket_policy(tag_bucket_name)
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 获取存储策略成功"
            self.back_dict['policy'] = policy
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 获取存储策略失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 给指定的存储桶设置存储桶策略
    def get_set_bucket_policy(self, tag_bucket_name, policy):
        '''

        :param tag_bucket_name: 当前桶名称
        :param policy: 存储桶策略
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            '''
            # 示例 ： 
            policy = """
            {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "AWS": "arn:aws:iam::123456789012:user/Alice"
                        },
                        "Action": [
                            "s3:GetObject",
                            "s3:PutObject"
                        ],
                        "Resource": "arn:aws:s3:::test1/*"
                    }

                ]
            }
            """
            '''
            self.minioClient.set_bucket_policy(tag_bucket_name, policy)
            self.back_dict['msg'] = f"目标存储桶 存储策略 设置成功"
            # self.back_dict['policy'] = policy
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 设置存储策略失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 获取存储桶的通知配置（成功）
    def get_bucket_notification(self, tag_bucket_name=None):
        '''

        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            notification = self.minioClient.get_bucket_notification(tag_bucket_name)
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 获取成功"
            self.back_dict['notification'] = notification
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 获取失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 设置存储桶的通知配置（失败）
    def re_set_bucket_notification(self, notification_config, tag_bucket_name=None):
        '''

        :param notification_config: 通知配置
        :param tag_bucket_name: 当前桶名称
        :return: 返回信息字典
        '''
        '''
        Example::
            config = NotificationConfig(
                queue_config_list=[
                    QueueConfig(
                        "QUEUE-ARN-OF-THIS-BUCKET",
                        ["s3:ObjectCreated:*"],
                        config_id="1",
                        prefix_filter_rule=PrefixFilterRule("abc"),
                    ),
                ],
            )
        :param notification_config: 通知配置
        :param tag_bucket_name: 目标桶
        :return:
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            # 设置存储桶的通知配置
            res = self.minioClient.set_bucket_notification(tag_bucket_name, config=notification_config)
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 设置成功"
            self.back_dict['notification_config'] = notification_config
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['tag_bucket_name'] = tag_bucket_name
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 设置失败"
            self.back_dict['error'] = err
            self.back_dict['notification_config'] = notification_config
        return self.back_dict

    # 移除存储桶上的所有通知（失败）
    def re_remove_all_bucket_notifications(self, tag_bucket_name=None):
        '''

        :param tag_bucket_name: 存储桶的名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            # 移除存储桶上的所有通知
            res = self.minioClient.delete_bucket_notification(tag_bucket_name)
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 移除成功"
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 通知配置 移除失败"
            self.back_dict['error'] = err
        return self.back_dict

    # 监听存储桶的通知
    def listen_bucket_notification(self, prefix, suffix, events, tag_bucket_name=None):
        '''

        :param prefix: 对象前缀，用于匹配以指定前缀开头的对象。可选参数，默认为空字符串。
        :param suffix:对象后缀，用于匹配以指定后缀结尾的对象。可选参数，默认为空字符串。
        :param events: 需要监听的事件类型。可选参数，默认为`s3:ObjectCreated:*`、`s3:ObjectRemoved:*`、`s3:ObjectAccessed:*`三种事件类型。
        :param tag_bucket_name: 存储桶的名称
        :return: 返回信息字典
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            # 监听存储桶的通知
            for event in self.minioClient.listen_bucket_notification(tag_bucket_name, prefix=prefix, suffix=suffix,
                                                                     events=events):
                self.back_dict['result'] = True
                self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 监听成功"
                self.back_dict['event'] = event
                return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_bucket_name} 监听失败"
            self.back_dict['error'] = err
            return self.back_dict


class FileOperation():
    def __init__(self, bucket_obj):
        '''

        :param bucket_obj: 存储桶对象 (必传)
        minioClient ： 父类的链接对象
        back_dict ： 返回信息字典
        get_tag_bucket_name : 校验当前桶对象
        '''
        self.minioClient = bucket_obj.minioClient
        self.bucket_name = bucket_obj.bucket_name
        self.back_dict = bucket_obj.back_dict
        self.get_tag_bucket_name = bucket_obj.get_tag_bucket_name

    # 从桶中下载一个对象（支持txt、csv文件）并保存到指定路径
    def load_object(self, save_file_path, tag_file_name, tag_bucket_name=None, start=0, end=0):
        '''

        :param save_file_path: 保存文件的路径
        :param tag_file_name: 桶名称
        :param tag_bucket_name: 文件名称
        :param start: 区间起始位置
        :param end:  区间结束位置
        :return: 下载成功或失败的提示信息
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            data = self.minioClient.get_object(tag_bucket_name, tag_file_name, start, end)  # 这里的data 是 WEBP 格式的数据
            type_save_file_path = os.path.join(save_file_path, tag_file_name)
            with open(type_save_file_path, 'wb') as file_data:
                for d in data.stream(32 * 1024):
                    file_data.write(d)
            type_file = tag_file_name.split('.')[-1].upper()
            if type_file in ['PNG', 'JPG', 'WEBP', 'JPEG', 'GIF', 'TIFF', 'BMP', 'SVG']:
                # 将WEBP图片转换为指定格式
                image = Image.open(type_save_file_path).convert('RGB')
                image.save(type_save_file_path, f"{type_file}")
            else:
                ...
            self.back_dict['msg'] = f"目标文件 {tag_file_name} 下载成功"
            return self.back_dict
        except Exception as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标存储桶 {tag_file_name} 下载失败"
            self.back_dict['error'] = err
            return self.back_dict


    # 下载并将文件保存到本地
    def fget_object(self, save_file_path, tag_file_name, tag_bucket_name=None):
        """

        :param save_file_path: 保存文件的路径
        :param tag_bucket_name: 桶名称
        :param tag_file_name:  文件名称
        :return:
        """
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            save_file_path = os.path.join(save_file_path, tag_file_name)
            res = self.minioClient.fget_object(tag_bucket_name, tag_file_name, save_file_path)
            self.back_dict['msg'] = f"目标文件下载成功"
            self.back_dict['addr'] = save_file_path
            return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标文件 {tag_file_name} 下载失败"
            self.back_dict['error'] = err
            return self.back_dict

    # 拷贝对象存储服务上的源对象到一个新对象
    # 注：该API支持的最大文件大小是5GB
    # 可通过copy_conditions参数设置copy条件
    # 经测试copy复制28M的文件需要663ms; 1.8G的压缩包需要53s
    def get_copy_object(self, start_file_name, end_file_name=None, start_bucket_name=None, end_bucket_name=None):
        """
        拷贝对象存储服务上的源对象到一个新对象
        :param start_file_name: 源文件桶的文件名字
        :param start_bucket_name: 源文件桶对象
        :param end_file_name: 目标对象桶的文件名字
        :param end_bucket_name: 目标桶对象
        :param source_obj: source 对象 CopySource("my-sourcebucket", "my-sourceobject")
        :return:
        """
        tag_bucket_name = self.get_tag_bucket_name(end_bucket_name)
        if end_file_name:
            end_file_name = end_file_name
        else:
            end_file_name = start_file_name
        source_obj = CopySource(start_bucket_name, start_file_name)
        try:
            copy_result = self.minioClient.copy_object(tag_bucket_name, end_file_name, source_obj)
            self.back_dict['msg'] = f"源桶 :>> {start_bucket_name} 源文件 :>> {start_file_name} 目标桶 :>> {end_bucket_name} 目标文件 :>> {end_file_name} 拷贝成功"
            self.back_dict['copy_result'] = copy_result
            return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标文件 {start_file_name} 拷贝失败"
            self.back_dict['error'] = err
            return self.back_dict

    # 添加一个新的对象到对象存储服务
    """
    单个对象的最大大小限制在5TB。put_object在对象大于5MiB时，自动使用multiple parts方式上传。
    这样，当上传失败时，客户端只需要上传未成功的部分即可（类似断点上传）。
    上传的对象使用MD5SUM签名进行完整性验证。
    """
    def upload_object(self, upload_file_path, tag_bucket_name=None, tag_file_name=None, content_type=None):
        '''

        :param upload_file_path: 本地上传文件的路径
        :param tag_bucket_name: 目标存储桶
        :param tag_file_name:  当前存储文件在存储桶的文件名
        :param content_type: 存储文件的类型(可根据需要选择) 指定上传的数据类型 "application/json"、"image/jpeg"、"text/plain"等。
        :return:
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        # 不选择类型
        if not content_type:
            try:
                with open(upload_file_path, 'rb') as file_data:
                    file_stat = os.stat(upload_file_path)
                    res = self.minioClient.put_object(tag_bucket_name, tag_file_name, file_data, file_stat.st_size)
                    download_url = self.minioClient.presigned_get_object(bucket_name=tag_bucket_name,
                                                                         object_name=tag_file_name,
                                                                         expires=timedelta(days=7),
                                                                         response_headers={
                                                                             'x-amz-server-side-encryption': 'AES256'})
                self.back_dict['msg'] = f"目标桶 {tag_bucket_name} 目标文件 {tag_file_name} 上传成功"
                self.back_dict['download_url'] = download_url
                return self.back_dict
            except MinioException as err:
                self.back_dict['result'] = False
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 上传失败"
                self.back_dict['error'] = err
                return self.back_dict
        # 指定其他类型
        else:
            try:
                with open(upload_file_path, 'rb') as file_data:
                    file_stat = os.stat(upload_file_path)
                    self.minioClient.put_object(tag_bucket_name, tag_file_name, file_data, file_stat.st_size,
                                                content_type=content_type)
                    download_url = self.minioClient.presigned_get_object(bucket_name=tag_bucket_name,
                                                                         object_name=tag_file_name,
                                                                         expires=timedelta(days=7),
                                                                         response_headers={
                                                                             'x-amz-server-side-encryption': 'AES256'})
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 文件类型 {content_type} 上传成功"
                self.back_dict['download_url'] = download_url
                return self.back_dict
            except MinioException as err:
                self.back_dict['result'] = False
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 文件类型 {content_type} 上传失败"
                self.back_dict['error'] = err
                return self.back_dict

    # 通过文件上传到对象中
    def fput_object(self, tag_file_name=None, tag_bucket_name=None, upload_file_path=None, content_type=None):
        '''

        :param upload_file_path: 本地上传文件的路径
        :param tag_bucket_name: 目标存储桶
        :param tag_file_name:  当前存储文件在存储桶的文件名
        :param content_type: 存储文件的类型(可根据需要选择) 指定上传的数据类型 "application/json"、"image/jpeg"、"text/plain"等。
        :return:
        '''
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        if not content_type:
            try:
                res = self.minioClient.fput_object(tag_bucket_name, tag_file_name, upload_file_path)
                # 返回一个下载链接 ： 有效期 7 天
                download_url = self.minioClient.presigned_get_object(bucket_name=tag_bucket_name,
                                                                     object_name=tag_file_name,
                                                                     expires=timedelta(days=7),
                                                                     response_headers={
                                                                         'x-amz-server-side-encryption': 'AES256'})
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 上传成功"
                self.back_dict['download_url'] = download_url
                return self.back_dict
            except MinioException as err:
                self.back_dict['result'] = False
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 上传失败"
                self.back_dict['error'] = err
                return self.back_dict
        else:
            try:
                res = self.minioClient.fput_object(tag_bucket_name, tag_file_name, upload_file_path,
                                                   content_type=content_type)
                download_url = self.minioClient.presigned_get_object(bucket_name=tag_bucket_name,
                                                                     object_name=tag_file_name,
                                                                     expires=timedelta(days=7),
                                                                     response_headers={
                                                                         'x-amz-server-side-encryption': 'AES256'})
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 文件类型 {content_type} 上传成功"
                self.back_dict['download_url'] = download_url
                return self.back_dict
            except MinioException as err:
                self.back_dict['result'] = False
                self.back_dict['msg'] = f"目标文件 {tag_file_name} 文件类型 {content_type} 上传失败"
                self.back_dict['error'] = err
                return self.back_dict

    # 获取对象的元数据
    def re_stat_object(self, tag_bucket_name=None, tag_file_name=None):
        '''

        :param tag_bucket_name: 目标存储桶
        :param tag_file_name:  当前存储文件在存储桶的文件名
        :return:
        '''

        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            stat = self.minioClient.stat_object(tag_bucket_name, tag_file_name)
            self.back_dict['msg'] = f"目标文件 {tag_file_name}  元数据获取成功"
            self.back_dict['stat'] = stat
            return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标文件 {tag_file_name}  元数据获取失败"
            self.back_dict['error'] = err
            return self.back_dict

    # 删除对象
    def remove_object(self, tag_file_name=None, tag_bucket_name=None):
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)
        try:
            res = self.minioClient.remove_object(tag_bucket_name, tag_file_name)
            self.back_dict['msg'] = f"目标对象 {tag_file_name}  删除成功"
            return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标对象 {tag_file_name}  删除失败"
            self.back_dict['error'] = err
            return self.back_dict

    # 删除存储桶中的多个对象
    def remove_objects(self, tag_bucket_name=None, tag_file_name_list=None):
        tag_bucket_name = self.get_tag_bucket_name(tag_bucket_name)

        try:
            # tag_file_name_list = ['1.txt', '2.txt', '3.txt']
            delete_object_list = []
            for tag_file_name in tag_file_name_list:
                delete_object_list.append(DeleteObject(tag_file_name))
            for del_err in self.minioClient.remove_objects(tag_bucket_name, delete_object_list):
                msg = f"目标桶 {tag_bucket_name}  目标文件 {del_err} 删除成功 "  # 源码里面会打印东西，但是我这里没法印出来，没搞懂
                print(msg)
            self.back_dict['msg'] = f"目标对象列表 {tag_file_name_list}  删除成功"
            return self.back_dict
        except MinioException as err:
            self.back_dict['result'] = False
            self.back_dict['msg'] = f"目标对象列表 {tag_file_name_list}  删除失败"
            self.back_dict['error'] = err
            return self.back_dict

    # 删除一个未完整上传的对象(失败)
    def remove_incomplete_upload(self, tag_bucket_name=None, tag_file_name=None):
        # 没有这个方法
        # 主动创建桶 tag_bucket_name 有值
        if tag_bucket_name:
            tag_bucket_name = tag_bucket_name
        else:
            tag_bucket_name = self.bucket_name
        try:
            self.minioClient.remove_incomplete_upload(tag_bucket_name, tag_file_name)
            msg = f"目标桶 {tag_bucket_name}  目标文件 {tag_file_name} 删除成功 "
            print(msg)
        except MinioException as err:
            msg = f"目标桶 {tag_bucket_name} 目标文件 {tag_file_name} 删除失败 失败原因 {err}"
            print(msg)


if __name__ == '__main__':
    ...
